// 客户端  -- 通信一端

// 1. 创建套接字
// 2. 不用显示绑定
// 3. 发消息

#include <iostream>
#include "Log.hpp"
#include "Common.hpp"
#include "InteInfo.hpp"
#include "Thread.hpp"

using namespace LogModel;
using namespace ThreadModel;

void Usage()
{
    std::cerr << "Usage : ./clinet  server_ip  server_port " << std::endl;
}

int sockfd = 0;
std::string server_ip;
uint16_t server_port = 0;
pthread_t id;

void Recv()
{
    while (true)
    {
        char buffer[1024];
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        int m = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);
        if (m > 0)
        {
            buffer[m] = 0;
            std::cerr << buffer << std::endl; // 2
        }
    }
}

void Send()
{
    // sendto -- 要知道给谁发
    // 就是给服务端发
    // 构建服务端网络信息

    // 手动构建
    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    // 本地转网络
    server.sin_port = htons(server_port);
    server.sin_addr.s_addr = inet_addr(server_ip.c_str());

    const std::string online = "inline";
    sendto(sockfd, online.c_str(), online.size(), 0, (struct sockaddr *)&server, sizeof(server));

    while (true)
    {
        std::string input;
        std::cout << "Please Enter# "; // 1
        std::getline(std::cin, input); // 0

        int n = sendto(sockfd, input.c_str(), input.size(), 0, (struct sockaddr *)&server, sizeof(server));
        (void)n;
        if (input == "QUIT")
        {
            pthread_cancel(id);
            break;
        }
    }
}

// ./client server_ip server_port
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage();
        exit(USAGE_ERROR);
    }

    // 获取命令行 server_ip server_port
    server_ip = argv[1];
    server_port = std::stoi(argv[2]);

    // 1 . 创建套接字
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        LOG(LogLevel::FATAL) << "socket error";
        exit(SOCKET_ERROR);
    }
    LOG(LogLevel::INFO) << "socket success";

    // 2. 绑定 -- 客户端不用显示绑定 , 系统自动绑定

    // 3. 构建网络信息 , 客户端有服务器 ip 和 端口
    // 本地转网络
    InteInfo server(server_ip, server_port);

    // 创建多线程
    //  1 . 一个专门发消息
    //  2 . 一个专门接收消息

    Thread sendthread(Send);
    Thread recvthread(Recv);
    
    sendthread.Start();
    recvthread.Start();

    sendthread.Join();
    recvthread.Join();

    return 0;
}